// 可视域分析
function getHeading(fromPosition, toPosition) {
    let finalPosition = new Cesium.Cartesian3();
    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
    Cesium.Matrix4.inverse(matrix4, matrix4);
    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
    return Cesium.Math.toDegrees(Math.atan2(finalPosition.x, finalPosition.y));
}
 
function getPitch(fromPosition, toPosition) {
    let finalPosition = new Cesium.Cartesian3();
    let matrix4 = Cesium.Transforms.eastNorthUpToFixedFrame(fromPosition);
    Cesium.Matrix4.inverse(matrix4, matrix4);
    Cesium.Matrix4.multiplyByPoint(matrix4, toPosition, finalPosition);
    Cesium.Cartesian3.normalize(finalPosition, finalPosition);
    return Cesium.Math.toDegrees(Math.asin(finalPosition.z));
}
import viewglsl from '@/assets/js/Video3d/viewglsl'
// import glsl from '@/assets/js/Video3d/glsl'
export default class ViewShedStage{

    constructor(viewer, options) {
        this.viewer = viewer;
        // 视点起始点
        this.viewPosition = options.viewPosition;
        // 视点结束点
        this.viewPositionEnd = options.viewPositionEnd;
        // 距离
        this.viewDistance = this.viewPositionEnd ? Cesium.Cartesian3.distance(this.viewPosition, this.viewPositionEnd) : (options.viewDistance || 100.0);
        // 视点姿势--heading
        this.viewHeading = this.viewPositionEnd ? getHeading(this.viewPosition, this.viewPositionEnd) : (options.viewHeading || 0.0);
        // 视点姿势--pitch
        this.viewPitch = this.viewPositionEnd ? getPitch(this.viewPosition, this.viewPositionEnd) : (options.viewPitch || 0.0);
        // 水平夹角
        this.horizontalViewAngle = options.horizontalViewAngle || 90.0;
        // 垂直夹角
        this.verticalViewAngle = options.verticalViewAngle || 60.0;
        // 可视区域颜色
        this.visibleAreaColor = options.visibleAreaColor || Cesium.Color.GREEN;
        // 不可视区域颜色
        this.invisibleAreaColor = options.invisibleAreaColor || Cesium.Color.GRAY;
        this.enabled = (typeof options.enabled === "boolean") ? options.enabled : true;
        this.softShadows = (typeof options.softShadows === "boolean") ? options.softShadows : true;
        this.size = options.size || 2048;
        this.update();
        this.url ="http://121.4.131.58:8000/images/xdl33.mp4";
        if(this.url){
            this.createVideoTexture();
        }
    }


    createVideoTexture(){
        this.videoId = "visualDomId";
        var t = document.createElement("SOURCE");
        t.type = "video/mp4",
            t.src = this.url;
        var i = document.createElement("SOURCE");
        i.type = "video/quicktime",
            i.src = this.url;
        var xdv = document.createElement("SOURCE");
        xdv.type = "application/x-mpegURL"
        xdv.src = this.url;
        var a = document.createElement("VIDEO");
        a.style.cssText = 'position:absolute; z-index:100; top:10px; left:10px; width:600px; height:300px;'
        // a.style.display ='none';
        a.play
        document.body.appendChild(a);
        a.id = this.videoId;
        a.appendChild(t);
        a.setAttribute("autoplay", !0),
            a.setAttribute("class", "video-js"),
            a.setAttribute("preload", "auto"),
            a.setAttribute("muted", "muted"),
            a.setAttribute("autoplay", "autoplay"),
            a.setAttribute('controls', 'controls'),
            a.setAttribute("loop", !0),
            a.setAttribute("crossorigin", !0)
        if(a){
            this.activeVideoListener || (this.activeVideoListener =  () =>{
                this.videoTexture && this.videoTexture.destroy(),
                    this.videoTexture = new Cesium.Texture({
                        context: viewer.scene.context,
                        source: a,
                        width: 1,
                        height: 1,
                        pixelFormat: Cesium.PixelFormat.RGBA,
                        pixelDatatype: Cesium.PixelDatatype.UNSIGNED_BYTE
                    })
            }),

            //监听器绑定时钟事件，每次都新建纹理，纹理的source是video
            viewer.clock.onTick.addEventListener(this.activeVideoListener)
        }

    }



    add() {
        this.createLightCamera();
        this.createShadowMap();
        this.createPostStage();
        this.drawFrustumOutline();
        this.drawSketch();
    }
    update(){
        this.clear();
        this.add();
    }
    clear(){

        if (this.sketch) {
            this.viewer.entities.removeById(this.sketch.id);
            this.sketch = null;
        }
        if (this.frustumOutline) {
            this.frustumOutline.destroy();
            this.frustumOutline = null;
        }
        if (this.postStage) {
            this.viewer.scene.postProcessStages.remove(this.postStage);
            this.postStage = null;
        }

    }


createLightCamera() {
    this.lightCamera = new Cesium.Camera(this.viewer.scene);
    this.lightCamera.position = this.viewPosition;
    // if (this.viewPositionEnd) {
    //     let direction = Cesium.Cartesian3.normalize(Cesium.Cartesian3.subtract(this.viewPositionEnd, this.viewPosition, new Cesium.Cartesian3()), new Cesium.Cartesian3());
    //     this.lightCamera.direction = direction; // direction是相机面向的方向
    // }
    this.lightCamera.frustum.near = this.viewDistance * 0.001;
    this.lightCamera.frustum.far = this.viewDistance;
    const hr = Cesium.Math.toRadians(this.horizontalViewAngle);
    const vr = Cesium.Math.toRadians(this.verticalViewAngle);
    const aspectRatio =
        (this.viewDistance * Math.tan(hr / 2) * 2) /
        (this.viewDistance * Math.tan(vr / 2) * 2);
    this.lightCamera.frustum.aspectRatio = aspectRatio;
    if (hr > vr) {
        this.lightCamera.frustum.fov = hr;
    } else {
        this.lightCamera.frustum.fov = vr;
    }
    this.lightCamera.setView({
        destination: this.viewPosition,
        orientation: {
            heading: Cesium.Math.toRadians(this.viewHeading || 0),
            pitch: Cesium.Math.toRadians(this.viewPitch || 0),
            roll: 0
        }
    });
}
createShadowMap() {
    this.shadowMap = new Cesium.ShadowMap({
        context: (this.viewer.scene).context,
        lightCamera: this.lightCamera,
        pointLightRadius: this.viewDistance,

        enabled: this.enabled,
        isPointLight: true,
        cascadesEnabled: false,
        size: this.size,
        softShadows: this.softShadows,
        normalOffset: false,
        fromLightSource: false,


        
    });
    this.viewer.scene.shadowMap = this.shadowMap;
}

createPostStage() {
    const fs = viewglsl;
    // const fs =glsl;
    const postStage = new Cesium.PostProcessStage({
        fragmentShader: fs,
        uniforms: {
            videoTexture:  () =>{
                return this.videoTexture;
            },
            shadowMap_textureCube: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_shadowMapTexture");
            },
            shadowMap_matrix: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_shadowMapMatrix");
            },
            shadowMap_lightPositionEC: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                return Reflect.get(this.shadowMap, "_lightPositionEC");
            },
            shadowMap_normalOffsetScaleDistanceMaxDistanceAndDarkness: () => {
                this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
                const bias = this.shadowMap._pointBias;
                return Cesium.Cartesian4.fromElements(
                    bias.normalOffsetScale,
                    this.shadowMap._distance,
                    this.shadowMap.maximumDistance,
                    0.0,
                    new Cesium.Cartesian4()
                );
            },
            shadowMap_texelSizeDepthBiasAndNormalShadingSmooth:  ()=> {
                var t = new Cesium.Cartesian2;
                const bias = this.shadowMap._pointBias;
                return t.x = 1 / this.shadowMap._textureSize.x,
                    t.y = 1 / this.shadowMap._textureSize.y,
                    Cesium.Cartesian4.fromElements(t.x, t.y, bias.depthBias, bias.normalShadingSmooth, this.combinedUniforms1)
            },
            // shadowMap_texelSizeDepthBiasAndNormalShadingSmooth: () => {
            //     this.shadowMap.update(Reflect.get(this.viewer.scene, "_frameState"));
            //     const bias = this.shadowMap._pointBias;
            //     const scratchTexelStepSize = new Cesium.Cartesian2();
            //     const texelStepSize = scratchTexelStepSize;
            //     texelStepSize.x = 1.0 / this.shadowMap._textureSize.x;
            //     texelStepSize.y = 1.0 / this.shadowMap._textureSize.y;
 
            //     return Cesium.Cartesian4.fromElements(
            //         texelStepSize.x,
            //         texelStepSize.y,
            //         bias.depthBias,
            //         bias.normalShadingSmooth,
            //         new Cesium.Cartesian4()
            //     );
            // },
            camera_projection_matrix: this.lightCamera.frustum.projectionMatrix,
            camera_view_matrix: this.lightCamera.viewMatrix,
            helsing_viewDistance: () => {
                return this.viewDistance;
            },
            helsing_visibleAreaColor: this.visibleAreaColor,
            helsing_invisibleAreaColor: this.invisibleAreaColor,
        }
    });
    this.postStage = this.viewer.scene.postProcessStages.add(postStage);
}

drawFrustumOutline() {
    const scratchRight = new Cesium.Cartesian3();
    const scratchRotation = new Cesium.Matrix3();
    const scratchOrientation = new Cesium.Quaternion();
    const position = this.lightCamera.positionWC;
    const direction = this.lightCamera.directionWC;
    const up = this.lightCamera.upWC;
    let right = this.lightCamera.rightWC;
    right = Cesium.Cartesian3.negate(right, scratchRight);
    let rotation = scratchRotation;
    Cesium.Matrix3.setColumn(rotation, 0, right, rotation);
    Cesium.Matrix3.setColumn(rotation, 1, up, rotation);
    Cesium.Matrix3.setColumn(rotation, 2, direction, rotation);
    let orientation = Cesium.Quaternion.fromRotationMatrix(rotation, scratchOrientation);
 
    let instance = new Cesium.GeometryInstance({
        geometry: new Cesium.FrustumOutlineGeometry({
            frustum: this.lightCamera.frustum,
            origin: this.viewPosition,
            orientation: orientation
        }),
        id: Math.random().toString(36).substr(2),
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(
                Cesium.Color.YELLOWGREEN//new Cesium.Color(0.0, 1.0, 0.0, 1.0)
            ),
            show: new Cesium.ShowGeometryInstanceAttribute(true)
        }
    });
 
    this.frustumOutline = this.viewer.scene.primitives.add(
        new Cesium.Primitive({
            geometryInstances: [instance],
            appearance: new Cesium.PerInstanceColorAppearance({
                flat: true,
                translucent: false
            })
        })
    );
}

drawSketch() {
    this.sketch = this.viewer.entities.add({
        name: 'sketch',
        position: this.viewPosition,
        orientation: Cesium.Transforms.headingPitchRollQuaternion(
            this.viewPosition,
            Cesium.HeadingPitchRoll.fromDegrees(this.viewHeading - this.horizontalViewAngle, this.viewPitch, 0.0)
        ),
        ellipsoid: {
            radii: new Cesium.Cartesian3(
                this.viewDistance,
                this.viewDistance,
                this.viewDistance
            ),
            // innerRadii: new Cesium.Cartesian3(2.0, 2.0, 2.0),
            minimumClock: Cesium.Math.toRadians(-this.horizontalViewAngle / 2),
            maximumClock: Cesium.Math.toRadians(this.horizontalViewAngle / 2),
            minimumCone: Cesium.Math.toRadians(this.verticalViewAngle + 7.75),
            maximumCone: Cesium.Math.toRadians(180 - this.verticalViewAngle - 7.75),
            fill: false,
            outline: true,
            subdivisions: 256,
            stackPartitions: 64,
            slicePartitions: 64,
            outlineColor: Cesium.Color.YELLOWGREEN
        }
    });
}
}

